//********************************************************
// KnightPopup.java
// Date: 5/1/2012
// Author: Andrew Landphier
//********************************************************
// Knight popup menu which dynamically allows only the available
// knight choices. To be chosen for the given direction. Dynamic choice updating
// has not been implemented (not enough time). To handle re-picking the repick
// button re-launches the knight window with the same origin constraints. The item choices
// are stored in a statically defined size array with the grid positions. Upon
// submitting, the array values will be populated and boardstate will be updated.
//*******************************************************
// EDITED by Jeff: Added the graphical representation of knight placement
//*******************************************************

package ui;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import java.awt.GridLayout;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Image;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import driver.Driver;
import functionality.Knight;
import functionality.Point;
import ui.data.BoardState;
import javax.swing.JButton;

public class KnightPopup extends JDialog implements ActionListener{

	
	private int tilecount = 1;	
	public Image img;
	
	private JDialog frame;
	private Frame parent;	
	//Panel action event happened at, panel for updating the knight menu
	private JPanel originPanel, panel;	
	//Title that shows the current knight count (updated upon selection)
	JLabel title;
	//X and Y location of the source panel
	private int gridX, gridY;
	//Point location of source panel
	private Point origin;	
	//Largest number of knights of the last selection
	private int maxPrevious = 0;
	//Selected number of knights
	private int maxChosen = 0;
	//temp number of knights the player has left
	private int knightsleft;
	private boolean done=false;
	//current number of knights in selection
	private int curKnightCount = 0;

	
	// Point locations correspond to the knight count
	private ArrayList<Point> tileLocation = new ArrayList<Point>(5);
	private ArrayList<Integer> knightCount = new ArrayList<Integer>(5);
	private ArrayList<BufferedImage> knightImages = new ArrayList<BufferedImage>();

	/**
	 * Create a new knight popup menu
	 * @param source (JPanel) Source panel in which the castle was placed.
	 * @param x (int) x position in the grid
	 * @param y (int) y position in the grid 
	 *  @author Andrew Landphier
	 */
	public KnightPopup(Frame frame, JPanel source, int x, int y) {
		parent = frame;
		this.frame = new JDialog(parent,"Knight Placement Menu", JDialog.DEFAULT_MODALITY_TYPE);
		knightsleft = Driver.getCurrentPlayer().getNumKnights();
		originPanel = source;
		gridX = x;
		gridY = y;
		origin = new Point(x,y);
		
	}
	
	/**
	 * Open the knight window and set it visable
	 *  @author Andrew Landphier
	 */
	public void Open(){
		initialize();
		frame.setVisible(true);
		frame.setFocusable(isFocused());
	}
	
	
	/**
	 * Initialize the window with the direction menu items and the buttons
	 *  @author Andrew Landphier 
	 */
	public void initialize(){ 
		frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		frame.setBounds(100, 100, 325, 325);
		JPanel contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		frame.setContentPane(contentPane);
		contentPane.setLayout(new GridLayout(0, 1, 0, 0));
		
		panel = new JPanel();
		contentPane.add(panel);
		GridBagLayout gbl_panel = new GridBagLayout();
		gbl_panel.columnWidths = new int[]{125, 100, 100, 0};
		gbl_panel.rowHeights = new int[]{20, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
		gbl_panel.columnWeights = new double[]{1.0, 1.0, 1.0, Double.MIN_VALUE};
		gbl_panel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
		panel.setLayout(gbl_panel);
		
		GridBagConstraints text = new GridBagConstraints();
		text.gridx = 0;
		text.gridy = 0;
		text.insets = new Insets(0, 0, 0, 0);
		text.anchor = GridBagConstraints.NORTHWEST;
		
		//Set the knight count
		title=new JLabel("Player " + Driver.getCountTurns()+" Knights left: "+ getKnightsLeft(), SwingConstants.LEFT);
		panel.add(title, text);
		
		// ************************ Direction from the origin you would like to place knights ***********************
		
		JLabel lblNewLabel = new JLabel("Direction: ");
		GridBagConstraints gbc_lblNewLabel = new GridBagConstraints();
		gbc_lblNewLabel.insets = new Insets(0, 0, 0, 0);
		gbc_lblNewLabel.anchor = GridBagConstraints.WEST;
		gbc_lblNewLabel.gridx = 0;
		gbc_lblNewLabel.gridy = 2;
		panel.add(lblNewLabel, gbc_lblNewLabel);

		JComboBox comboBox_Direction = new JComboBox();
		ArrayList<String> direction = getDirections();
		for (String s : direction) {
			comboBox_Direction.addItem(s);
		}
		
		comboBox_Direction.setSelectedIndex(0);
		comboBox_Direction.addActionListener(this);
		
		GridBagConstraints gbc_comboBox_Direction = new GridBagConstraints();
		gbc_comboBox_Direction.gridwidth = 2;
		gbc_comboBox_Direction.insets = new Insets(0, 0, 5, 8);
		gbc_comboBox_Direction.fill = GridBagConstraints.HORIZONTAL;
		gbc_comboBox_Direction.gridx = 1;
		gbc_comboBox_Direction.gridy = 2;
		
		panel.add(comboBox_Direction, gbc_comboBox_Direction);
		//*********************************************************************************************************
		
		
		//*****************************************************
		//************ Submit Button *************************
		//*****************************************************
		JButton btnSubmit = new JButton("Submit");
		GridBagConstraints gbc_btnSubmit = new GridBagConstraints();
		gbc_btnSubmit.insets = new Insets(0, 0, 0, 0);
		gbc_btnSubmit.gridx = 0;
		gbc_btnSubmit.gridy = 13;
		gbc_btnSubmit.anchor = GridBagConstraints.PAGE_END;
		ActionListener actionSubmit = new ActionListener()
		{
			public void actionPerformed(ActionEvent e) 
			{
				System.out.println("Current player knight count before: " + Driver.getCurrentPlayer().getNumKnights());
				Driver.getCurrentPlayer().removeNumKnights(curKnightCount);
				System.out.println("Current player knight count after: " + Driver.getCurrentPlayer().getNumKnights());

				ArrayList<JPanel> temp=new ArrayList<JPanel>();
				
				for (int i = 0; i < tileLocation.size(); i++)
				{
					//Updates the knight counts at the following locations
					BoardState.addKnight(tileLocation.get(i), knightCount.get(i));
					//Updates the board state with the top player 
					BoardState.setPlayer(tileLocation.get(i), Driver.getCurrentPlayer().getPlayerNum());
					BoardState.setMax(tileLocation.get(i), knightCount.get(i));
					
					if (BoardState.isMaxKnights(tileLocation.get(i))){
						Board.disablePanel(tileLocation.get(i));
					}
					//tiles have been added to boardstate via menupopup actionPerformed(ActionEvent e)
					//Drawing Knights onto board and set knights					
					Tile t=BoardState.findTile(tileLocation.get(i));
					
					//adds knight to tiles k
					ArrayList<Knight> k = new ArrayList<Knight>();
					int count=0;
					
					//add old knights to new array
					for(Knight q:t.getKnightList())
					{
						k.add(q);
						++count;						
					}
					//add new knights to new array k
					for (int y = count; y < BoardState.getKnight(tileLocation.get(i)); y++)
					{	
						k.add(new Knight(Driver.getCurrentPlayer().getColor()));
					}
					
					//replace tiles knights array with updated array k
					t.placeKnight(k);			
					
					//make knights image	
					//get landscape image
					BufferedImage label = t.getBufferedImage();
					BufferedImage label2=t.getBufferedImage();
					for(int p=0;p<t.getKnightList().size();++p)
					{
						
						
						BufferedImage label22 = null;
						try {
							
								if(t.getKnightColor(p).equals(Color.RED)){
									label22 = ImageIO.read(new File("ICONS/RedKnight.png"));
								}
								else if(t.getKnightColor(p).equals(Color.BLUE)){
									label22 = ImageIO.read(new File("ICONS/BlueKnight.png"));
								}
								else if(t.getKnightColor(p).equals(Color.GREEN)){
									label22 = ImageIO.read(new File("ICONS/GreenKnight.png"));
								}
								else if(t.getKnightColor(p).equals(Color.YELLOW)){
									label22 = ImageIO.read(new File("ICONS/YellowKnight.png"));
								}
								
							
						} catch (IOException e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
												
						//knightImages.add( label22.getScaledInstance(label.getWidth(), label.getHeight(), BufferedImage.SCALE_SMOOTH));
						knightImages.add(label22);
					}
					//knightPanels
					//save updated tile onto board SCALE_SMOOTH,
					BoardState.setTile(t);
					
					
					//JLabel x=new JLabel(new ImageIcon(label));
					//Dimension d = Driver.b.getGrid(tileLocation.get(i).getX(), tileLocation.get(i).getY()).getSize();
					
					//Dimension d = x.getSize();
					
					
					//overlay knights image
				
					Graphics2D g = null;					
					g=label2.createGraphics();	
	        		g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.9f));	        	
	        		int offset=0;
	        		for(BufferedImage t1: knightImages)
	        		{	        			//(t1.getHeight()) 
	        			int u=(label2.getHeight()-25)+offset;
	        			g.drawImage(t1,0,u, null);
	        			offset-=t1.getHeight()-10;
	        		}
	        		knightImages.clear();	
	        		Graphics2D g2 = label.createGraphics();		
	        		
	        		
	        		//g2.drawImage(label2, (label.getWidth()-label2.getWidth())/2, (label.getHeight()-label2.getHeight())/2, null);	        	
	        		//g2.drawImage(label2,label.getWidth()/2, label.getHeight()/2,null);	  
	        		g2.drawImage(label2,0, 0,null);
	        		//label.getWidth() label.getHeight()
	        		
	        		g2.dispose();
	        		g.dispose();
	        		JLabel label3 = new JLabel(new ImageIcon(label));	        		
	        		
	        		//get source jpanel
	                JPanel src=t.getPanel();	               
	                src.removeAll();
	                src.add(label3);
	        		src.revalidate();
	        	
				}
				done=true;
				frame.dispose();				
			}
		};
		
		btnSubmit.addActionListener(actionSubmit);
		panel.add(btnSubmit, gbc_btnSubmit);
		
		//*****************************************************
		//************ Repick Button *************************
		//*****************************************************
		JButton btnRepick = new JButton("Repick");
		GridBagConstraints gbc_btnRepick = new GridBagConstraints();
		gbc_btnRepick.insets = new Insets(0, 0, 0, 0);
		gbc_btnRepick.gridx = 1;
		gbc_btnRepick.gridy = 13;
		gbc_btnRepick.anchor = GridBagConstraints.PAGE_END;
		ActionListener actionRepick = new ActionListener(){
			public void actionPerformed(ActionEvent e) { 
				frame.dispose();
				KnightPopup kp = new KnightPopup(parent, originPanel, gridX, gridY);
				kp.Open();
			}
		};
		btnRepick.addActionListener(actionRepick);
		panel.add(btnRepick, gbc_btnRepick);
		
		//*****************************************************
		//************ Close Button *************************
		//*****************************************************
		JButton btnClose = new JButton("Close");
		GridBagConstraints gbc_btnClose = new GridBagConstraints();
		gbc_btnClose.gridx = 2;
		gbc_btnClose.gridy = 13;
		gbc_btnClose.insets = new Insets(0, 0, 0, 0);
		gbc_btnClose.anchor = GridBagConstraints.PAGE_END;
		ActionListener actionClose = new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				frame.dispose();
			}
		};
		
		btnClose.addActionListener(actionClose);
		panel.add(btnClose, gbc_btnClose);
		
		frame.pack();
	}
		
		
		
	/**
	 * Recursively adds knight count selection jcomboboxes to the source knight panel. Terminates additions upon,
	 * not enough tiles in hand, next addition requires more knights then available, next tile is invalid, next tile is full,
	 * no excess knights available to move to the next tile.
	 * @param direction direction placing tiles
	 * @param p source point
	 * @param choices available choices to create the menu with
	 */
	public void addTile(final String direction, final Point p, String[] choices) {
		JLabel lblTileOne = new JLabel(getTileLabel(tilecount));
		GridBagConstraints gbc_lblTileOne = new GridBagConstraints();
		gbc_lblTileOne.anchor = GridBagConstraints.WEST;
		gbc_lblTileOne.insets = new Insets(0, 0, 0, 0);
		gbc_lblTileOne.gridx = 0;
		gbc_lblTileOne.gridy = tilecount+2;
		panel.add(lblTileOne, gbc_lblTileOne);
		
		final JComboBox comboBox_Tile1 = new JComboBox(choices);
		comboBox_Tile1.setSelectedIndex(0);
		
		 ActionListener actionTile = new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				JComboBox tileBox = (JComboBox)e.getSource();
				
				//Make sure its a number being selected
				if (tileBox.getSelectedIndex() > 0){
					String knights = (String)tileBox.getSelectedItem();
					
					setPreviousChoice(Integer.valueOf(knights)); //remember your choice
					addKnightCount(Integer.valueOf(knights)); //add choice to arraylist of choices
					setKnightsLeft(Integer.valueOf(knights)); //decrement total knights
					setCurKnightCount(Integer.valueOf(knights)); //add cumulative knight count
					tileLocation.add(p); //add point location to arraylist
					
					updateTitle(getKnightsLeft());

					//Check if the player wanted to continue placing tiles
					if (direction != "None"){
						
						//Check if he has enough knights in his hand to continue
						if (getKnightsLeft() >= getCurKnightCount()) {
							
							//Check if there are valid tiles in the corresponding direction
							if (getCurKnightCount() < 5 && BoardState.checkValidTile(BoardState.directionInc(p, direction))) {
							
								//Get the selection choices and check if there are 
								String[] choices = getKnights(BoardState.directionInc(p, direction), direction, getCurKnightCount(),  getMaxDiff());
								if (choices.length > 0){
									tilecount++;
									setPreviousMax(Integer.valueOf(choices[(choices.length-1)]));
									addTile(direction, BoardState.directionInc(p, direction), choices);
									
								}
							}
						}
					}
					comboBox_Tile1.setEnabled(false);
				}
			}
		};
		
		comboBox_Tile1.addActionListener(actionTile);
		GridBagConstraints gbc_comboBox_Tile1 = new GridBagConstraints();
		gbc_comboBox_Tile1.gridwidth = 2;
		gbc_comboBox_Tile1.insets = new Insets(0, 0, 5, 8);
		gbc_comboBox_Tile1.fill = GridBagConstraints.HORIZONTAL;
		gbc_comboBox_Tile1.gridx = 1;
		gbc_comboBox_Tile1.gridy = tilecount+2;
		panel.add(comboBox_Tile1, gbc_comboBox_Tile1);
		panel.revalidate();
		frame.pack();
	}
	
	
	/**
	 * Action listener to handle the first direction selection
	 * (Note could use a location defined action listener too)
	 *@author Andrew Landphier
	 */
	public void actionPerformed(ActionEvent e) {
		JComboBox directionBox = (JComboBox)e.getSource();
		String direction = (String)directionBox.getSelectedItem();
		directionBox.setEnabled(false);
		
		//Max amount of knights a user would be able to place = 5 or how many knights they have.
		if (Driver.getCurrentPlayer().getNumKnights() > 5){
			setPreviousMax(5);
		} else {
			setPreviousMax(Driver.getCurrentPlayer().getNumKnights());
		}
		
	
		String[] choices = getKnights(origin, direction, getCurKnightCount(), getMaxDiff());
		if(choices.length > 0 )
			addTile(direction, origin, choices);
	}
	

	/**
	 * Uses the boardstate class to retrieve the minimum to the maximum amount of knights that
	 * are able to be placed on the board.
	 * @param p (point) you are placing knights on
	 * @param direction (string) direction heading (uses Driver static strings)
	 * @param curKnightCount (int) number of knights available to place
	 * @paran maxdiff (int) differential of max and chosen of the previous tile
	 * @return String[] values 1-4, returns 0 if no choice available
	 * @author Andrew Landphier
	 */
	public static String[] getKnights(Point p, String direction, int curKnightCount, int maxdiff){
		int maxKnights = BoardState.getMaxKnights(p, direction, curKnightCount);
		int minKnights = BoardState.getMinKnights(p, curKnightCount, Driver.getCurrentPlayer());

		int count = minKnights;
		
		//Simulate the movement of tiles from one tile to another
		if (maxdiff < maxKnights) maxKnights = maxdiff;
		
		//If the players addition is 4 for specific tile
		//Reduce the max by one
		if (BoardState.isMax(p, Driver.getCurrentPlayer(), maxKnights)){
			maxKnights -= 1;
		}
		
		//Set max to difference and iterate up to the max
		int max = maxKnights - minKnights;
		String[] items;
		
		if (max+1 > 0) {
			items = new String[max+2];
			items[0] = "Select new"; //Set Initial item
			for (int i = 1; i < max+2; i++) {
				items[i] = String.valueOf(count);
				count++;
			}
		} else {
			items = new String[0];
		}
		return items;
	}
	
	//*************** SETTERS **************************************
		private void addKnightCount(int iknight){knightCount.add(iknight);} //Add choice to arraylist of choices
		private void setPreviousMax(int prev){maxPrevious = prev;} //Previous max amount of knights
		private void setPreviousChoice(int prev) {maxChosen = prev;} //Previous numbers of knights
		private void setCurKnightCount(int addknight){curKnightCount += addknight;} //Option box knight count
		private void setKnightsLeft(int minusKnights){ knightsleft -= minusKnights;}
		
		//Update the title with the 
		private void updateTitle(int iknights){
			title.setText("Player " + Driver.getCountTurns()+" Knights left: "+ getKnightsLeft());
			title.setAlignmentX(SwingConstants.LEFT);
			title.revalidate();
		}
		
		
	
	//****************** GETTERS ******************************
		private int getMaxDiff() {return maxPrevious-maxChosen;} //simulate movement
		private int getKnightsLeft(){return knightsleft;} // knights left in players pool
		private int getCurKnightCount(){return curKnightCount;} //current number of knights used
		public ArrayList<Point> getGridPoints(){return tileLocation;} //array of tile location points relative to the grid
		public ArrayList<Integer> getKnightCounts(){return knightCount;} // array of knight counts at the tile locations
		
		
		/**
		 * Get the label for the knight popup menu JComboBox's
		 * @param i = number of combo 
		 * @return String Tile Label
		 * @author Andrew Landphier
		 */
		private String getTileLabel(int i){
			String out;
			if (i == 1) {
				out = "Origin Tile ";
			} else if (i == 2) {
				out = "Tile Two ";
			} else if (i == 3) {
				out = "Tile Three";
			} else if (i ==4 ){
				out = "Tile Four";
			} else 
				out = "Tile Five";
			return out;
		}
		
		/**
		 * Get the Array of direction choices
		 * @return Arraylist of directions
		 * @author Andrew Landphier
		 */
		private ArrayList<String> getDirections(){
			ArrayList<String> al = new ArrayList<String>();
			
			al.add("Select new");
			
			// north
			if (BoardState.checkValidTile(new Point(gridX-1, gridY))) {
				al.add("Place Knight "+Driver.NORTH);
			}
			// south
			if 	(BoardState.checkValidTile(new Point(gridX+1, gridY))) {
				al.add("Place Knight "+Driver.SOUTH);
			}	
			//east
			if (BoardState.checkValidTile(new Point(gridX, gridY+1))) { 
				al.add("Place Knight "+Driver.EAST);
			}
			//west
			if 	(BoardState.checkValidTile(new Point(gridX, gridY-1))) {
				al.add("Place Knight "+Driver.WEST);
			}
			
			al.add("None");
			return al;
		}
		
		public boolean isDone()
		{
			return done;
		}
}